<template>
  <div class="vs-code">
    <vs-code-tip />
    <div class="vs-code-content" @mousedown.stop @dblclick.stop>
      <div class="vs-code-nav">
        <div class="tools">
          <span class="checked"><i class="iconfont wos-document" /></span>
          <span><i class="iconfont wos-search-left" /></span>
          <span><i class="iconfont wos-git" /></span>
          <span><i class="iconfont wos-plugin" /></span>
        </div>
      </div>
      <div class="vs-code-folder">
        <div class="no-data" v-if="!dirList">
          <p class="pb20">尚未打开文件夹</p>
          <div class="open-dir" @click="handleOpenDir">打开文件夹</div>
        </div>
        <template v-else>
          <vs-code-menu :data="dirList" :checked-id="currentData?.id" open @checked-file="handleCheckedMenuFile" />
        </template>
      </div>
      <div v-if="tabList.length" class="vs-code-code">
        <ul class="tab-list" ref="tabListDom">
          <li
            v-for="(item, index) in tabList"
            :key="item.id"
            :class="{ checked: currentData?.id === item.id }"
            @click="handleCheckTab(item, $event)"
          >
            <vs-code-icon :name="item.name" />
            <em class="pl10 pr10 fs14">{{ item.name }}</em>
            <span @click.stop="handleCloseTab(item.id, index)"><i class="iconfont wos-close-wechat" /></span>
          </li>
        </ul>
        <div class="path">{{ currentData?.path }}</div>
        <div v-if="currentData?.type === 'text'" class="text-code">
          <highlightjs style="width: 100%; height: 100%" :language="currentData.suffix" :code="currentData.content" />
        </div>
        <div v-else-if="currentData?.type === 'image'" class="text-code">
          <img :src="currentData?.content" alt="pic" />
        </div>
        <div v-else class="text-code">
          <div class="no-data fs14">
            <i class="iconfont wos-vscode fs200" />
            <span class="pt30">此文件是二进制文件或使用了不受支持的文本编码，所以无法在文本编辑器中显示。</span>
          </div>
        </div>
      </div>
      <div v-else class="vs-code-code">
        <div class="no-data">
          <img src="@/assets/images/vscode/vscode.png" alt="vscode" />
        </div>
      </div>
    </div>
  </div>
</template>

<script setup lang="ts">
import VsCodeTip from '@/components/systemWindow/vsCode/vsCodeTip.vue'
import VsCodeMenu from '@/components/systemWindow/vsCode/vsCodeMenu.vue'
import VsCodeIcon from '@/components/systemWindow/vsCode/vsCodeIcon.vue'
import { ref } from 'vue'
import { getDirectoryPickerTree, getFileType, readFile } from '@/utils/utils'
import type { ShowDirectoryPicker } from '@/types/window'

interface ITabList {
  suffix: string
  name: string
  path: string
  id: string
  type: string
  content: string
}

const tabListDom = ref<HTMLElement>()
const dirList = ref<ShowDirectoryPicker | null>(null)
const tabList = ref<ITabList[]>([])
const currentData = ref<ITabList | null>(null)

const handleOpenDir = async () => {
  const dir = await showDirectoryPicker()
  dirList.value = await getDirectoryPickerTree(dir)
}

const findFileClass = (filename: string): string => {
  const fileType = getFileType(filename)
  const classType = [
    {
      type: 'text',
      list: [
        'vue',
        'ts',
        'js',
        'css',
        'less',
        'scss',
        'style',
        'html',
        'json',
        'cjs',
        'lock',
        'txt',
        'py',
        'java',
        'xml'
      ]
    },
    { type: 'image', list: ['png', 'jpg', 'jpeg', 'gif'] }
  ]
  return classType.find((item) => item.list.includes(fileType))?.type || ''
}

const handleCloseTab = (id: string, index: number) => {
  if (currentData.value?.id === id) {
    currentData.value = tabList.value[index + 1]
      ? tabList.value[index + 1]
      : tabList.value[index - 1]
        ? tabList.value[index - 1]
        : null
  }
  tabList.value = tabList.value.filter((item) => item.id !== id)
}

const handleCheckTab = (data: ITabList, ev: MouseEvent) => {
  if (!tabListDom.value) return
  const target = ev.target as HTMLElement
  const li = target.tagName.toLowerCase() === 'li' ? target : (target.parentElement as HTMLElement)
  currentData.value = data
  tabListDom.value?.scrollTo(li.offsetLeft - 290, 0)
}

const handleCheckedMenuFile = async (data: ShowDirectoryPicker) => {
  const findTab = tabList.value.find((item) => item.id === data.id)
  if (findTab) {
    currentData.value = findTab
    return
  }
  const file = await data.getFile()
  const type = findFileClass(file.name)
  const content = type === 'text' ? await readFile(file) : type === 'image' ? await readFile(file, 'toBase64') : ''
  currentData.value = {
    suffix: getFileType(file.name),
    name: data.name,
    path: data.path,
    id: data.id,
    type,
    content
  }
  tabList.value.push(currentData.value)
}
</script>

<style scoped lang="scss">
.vs-code {
  width: 100%;
  height: 100%;
  color: rgb(134, 134, 134);
  background-color: rgb(24, 24, 24);

  .vs-code-content {
    display: flex;
    width: 100%;
    height: calc(100% - 41px);

    .vs-code-nav {
      width: 60px;
      min-width: 60px;
      height: 100%;
      box-sizing: border-box;
      border-right: 1px solid rgb(43, 43, 43);
      background-color: rgb(24, 24, 24);

      .tools {
        display: flex;
        flex-direction: column;
        align-items: center;

        > span {
          position: relative;
          display: inline-flex;
          justify-content: center;
          align-items: center;
          width: 100%;
          height: 50px;

          &.checked {
            color: #fff;

            &::after {
              content: '';
              position: absolute;
              left: 0;
              top: 0;
              width: 1px;
              height: 100%;
              background-color: #fff;
            }
          }

          > .iconfont {
            font-size: 22px;
            font-weight: 100;
          }
        }
      }
    }

    .vs-code-folder {
      width: 230px;
      min-width: 230px;
      padding: 0 20px;
      height: 100%;
      box-sizing: border-box;
      border-right: 1px solid rgb(43, 43, 43);
      background-color: rgb(24, 24, 24);
      overflow: auto;

      .no-data {
        color: rgb(97, 97, 97);
        font-size: 16px;
        padding-top: 20px;

        .open-dir {
          cursor: pointer;
          display: flex;
          justify-content: center;
          align-items: center;
          height: 30px;
          color: #fff;
          background-color: rgb(0, 120, 212);

          &:hover {
            background-color: rgb(2, 110, 193);
          }
        }
      }
    }

    .vs-code-code {
      width: calc(100% - 60px - 230px);
      height: 100%;

      .tab-list {
        width: 100%;
        height: 31px;
        display: flex;
        align-items: center;
        overflow-x: auto;

        &::-webkit-scrollbar {
          width: auto;
          height: 2px;
        }

        &::-webkit-scrollbar-thumb {
          height: 2px;
          background-color: #333;
          border-radius: 1px;
        }

        > li {
          white-space: nowrap;
          cursor: pointer;
          display: flex;
          align-items: center;
          height: 100%;
          padding: 0 25px 0 20px;
          color: rgb(157, 157, 157);
          position: relative;
          box-sizing: border-box;

          &.checked {
            color: #fff;

            &::after {
              content: '';
              position: absolute;
              left: 0;
              bottom: 0;
              width: 100%;
              height: 1px;
              background-color: rgb(128, 203, 198);
            }
          }

          &:hover {
            > span {
              display: inline-block;
            }
          }

          span {
            display: none;
            position: absolute;
            top: 50%;
            right: 10px;
            transform: translateY(-50%);
            width: 25px;
            height: 25px;
            line-height: 25px;
            text-align: center;
            border-radius: 4px;

            &:hover {
              background-color: rgb(50, 50, 50);
            }
          }
        }
      }

      .path {
        padding-left: 20px;
        height: 20px;
      }

      .text-code {
        width: 100%;
        height: calc(100% - 32px - 20px);
        overflow: auto;

        .no-data {
          width: 100%;
          height: 100%;
          display: flex;
          flex-direction: column;
          justify-content: center;
          align-items: center;
        }

        ::v-deep(.hljs) {
          font-size: 14px;
          width: 100%;
          height: 100%;
          box-sizing: border-box;
          background-color: transparent;
        }

        img {
          width: 100%;
          height: 100%;
          object-fit: contain;
          object-position: center center;
        }
      }

      .no-data {
        width: 100%;
        height: 100%;
        display: flex;
        justify-content: center;
        align-items: center;

        img {
          width: 80%;
          height: 80%;
          object-fit: contain;
        }
      }
    }
  }
}
</style>
